﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace HexEditor_
{
    public abstract class ConsoleInputMode
    {
        public abstract bool OnGetKey(ConsoleProgram prog, ConsoleKeyInfo key);
        public abstract bool EnterMode(ConsoleKeyInfo key);
        public abstract string GetModeName();
        public static bool IsValidChar(char ch)
        {
            return (ch >= 'a' && ch <= 'z') ||
                (ch >= 'A' && ch <= 'Z') ||
                (ch >= '0' && ch <= '9');
        }
    }
    public class EditMode : ConsoleInputMode
    {
        public override bool EnterMode(ConsoleKeyInfo key)
        {
            return true;
        }
        public override bool OnGetKey(ConsoleProgram prog, ConsoleKeyInfo key)
        {
            if (key.Key == ConsoleKey.Escape)
            {
                return true;
            }
            return false;
        }
        public override string GetModeName()
        {
            return "Edit";
        }
    }

    public class CommandMode : ConsoleInputMode
    {
        public string CurCmd { get; set; }

        public override bool EnterMode(ConsoleKeyInfo key)
        {
            return true;
        }

        void Help(ConsoleProgram prog)
        {
            string strHelp = "HexEditor 1.0.1\n\n";
            strHelp += "Command List    |   Description\n";
            strHelp += ":o                  Open file\n";
            strHelp += ":h                  Help\n";
            strHelp += ":q                  Exit\n";
            strHelp += ":dt                 Supported data type list\n";
            strHelp += "f                   Format Selected Data (char(default), int, float , double )";

            strHelp += "\nPress ESC to return ...\n";
                
            prog.Viewer.ShowContent(strHelp);
            ConsoleKeyInfo key = Console.ReadKey(true);
            while (key.Key != ConsoleKey.Escape)
            {
                key = Console.ReadKey(true);
            }
            prog.Viewer.OnDocUpdated();
        }

        void OpenFile(ConsoleProgram prog)
        {
            string strHelp = "Please input file path: \n";
            prog.Viewer.ShowContent(strHelp);

            
            string strFilePath = Console.ReadLine();
            strHelp += strFilePath;
            strHelp += "\nOpening file ...\n";

            prog.Viewer.ShowContent(strHelp);

            if (File.Exists(strFilePath))
            {
                HexDoc doc = prog.Editor.OpenFile(strFilePath);
                if (doc == null)
                {
                    strHelp += "Open failed...";
                }
                else
                {
                    strHelp += "Open success...";
                    prog.Viewer.Initialize();
                }
            }
            else
            {
                strHelp += "File is not exist";
            }
          
            if (prog.Editor.GetDoc(0) == null)
            {
                prog.Viewer.ShowContent(strHelp);
                System.Threading.Thread.Sleep(1000);
            }
            else
            {
                prog.Viewer.ShowContent(strHelp);
                System.Threading.Thread.Sleep(200);
            }
            prog.Viewer.OnDocUpdated();
        }

        void ShowDatatypeList(ConsoleProgram prog)
        {
            prog.Viewer.ShowDataTypeList(prog.Editor._DataTypeManager);
            Console.Write("\nPress ESC to return ...\n");

            ConsoleKeyInfo key = Console.ReadKey(true);
            while (key.Key != ConsoleKey.Escape)
            {
                key = Console.ReadKey(true);
            }
            prog.Viewer.OnDocUpdated();
        }

        public bool ProcessCmd(string strCmd, ConsoleProgram prog)
        {
            switch (strCmd)
            { 
                case ":o":
                case ":O":
                    OpenFile(prog);
                    break;
                case ":q":
                case ":Q":
                    return true;
                case ":H":
                case ":h":
                case "help":
                    Help(prog);
                    break;
                case ":dt":
                    ShowDatatypeList(prog);
                    break;
                default:
                    break;
            }
            return false;
        }

        //返回值表明info是否有有效输入如果为true
        public void ProcessFormat(ConsoleProgram prog)
        {
            string strStmt = "Format Data: ";
            string strType = "";
            ((ConsoleEditView)prog.Viewer).ShowCommand(strStmt);

            ConsoleKeyInfo info = Console.ReadKey(true);
            while (ConsoleInputMode.IsValidChar(info.KeyChar))
            {
                strType += info.KeyChar;
                strStmt = "Format Data: ";
                strStmt += strType;
                ((ConsoleEditView)prog.Viewer).ShowCommand(strStmt);
                info = Console.ReadKey(true);
            }
            if (info.Key == ConsoleKey.Enter)
            {
                int res = prog.Editor.GetDoc(0).SetFormatRange(prog.Editor,
                    strType,
                    ((ConsoleEditView)prog.Viewer).SelStart,
                    ((ConsoleEditView)prog.Viewer).SelEnd + 1);
                if (res < 0)
                {
                    prog.Viewer.ShowCommand(HexEditor.LastErrorMsg);
                }
                else
                {
                    prog.Viewer.OnDocUpdated();
                }
            }
        }

        bool ProgressImmediateCmd(ConsoleKeyInfo keyinfo, ConsoleProgram prog)
        {
            switch (keyinfo.KeyChar)
            {
                case 'F':
                case 'f':
                    ProcessFormat(prog);
                    break;
                default:
                    break;
            }
            return false;
        }

        public override bool OnGetKey(ConsoleProgram prog, ConsoleKeyInfo key)
        {
            if (key.Key == ConsoleKey.Enter)
            {
                if (CurCmd.Length > 0)
                {
                    bool res = ProcessCmd(CurCmd, prog);
                    CurCmd = "";
                    ((ConsoleEditView)prog.Viewer).ShowCommand(CurCmd);
                    return res;
                }
                return false;
            }
            else if (key.Key >= ConsoleKey.LeftArrow &&
                key.Key <= ConsoleKey.DownArrow)
            {
                switch (key.Key)
                {
                    case ConsoleKey.LeftArrow:
                        prog.Viewer.MoveCursorLeft((key.Modifiers & ConsoleModifiers.Shift) != 0);
                        break;
                    case ConsoleKey.RightArrow:
                        prog.Viewer.MoveCursorRight((key.Modifiers & ConsoleModifiers.Shift) != 0);
                        break;
                    case ConsoleKey.UpArrow:
                        prog.Viewer.MoveCursorUp((key.Modifiers & ConsoleModifiers.Shift) != 0);
                        break;
                    case ConsoleKey.DownArrow:
                        prog.Viewer.MoveCursorDown((key.Modifiers & ConsoleModifiers.Shift) != 0);
                        break;
                }
            }
            else if((CurCmd == null || CurCmd.Length == 0) && key.KeyChar != ':')//即时命令
            {
                return ProgressImmediateCmd(key, prog);
            }
            else if ((key.KeyChar >= '0' && key.KeyChar <= '9') || 
                (key.KeyChar >= 'a' && key.KeyChar <= 'z') ||
                (key.KeyChar >= 'A' && key.KeyChar <= 'Z') ||
                key.KeyChar == ' ' ||
                key.KeyChar == ':') //长命令
            {
                CurCmd += key.KeyChar;
                ((ConsoleEditView)prog.Viewer).ShowCommand(CurCmd);
            }
            
            return false;
        }
        public override string GetModeName()
        {
            return "Command";
        }
    }
}
